<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

  <title>PDF Viewer</title>
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
      overflow: hidden;
      font-family: sans-serif;
    }

    #container {
      display: flex;
      height: 100vh;
      width: 100vw;
      overflow: hidden;
    }

    #thumbnails {
      width: 83px;
      background: #ddd;
      overflow-y: auto;
      transition: width 0.3s;
    }

    #thumbnails.hidden {
      width: 0;
      overflow: hidden;
    }

    #thumbnails canvas {
      display: block;
      margin: 10px auto;
      border: 2px solid transparent;
      cursor: pointer;
      max-width: 67px;
      max-height: 180px;
    }

    #thumbnails canvas.active {
      border-color: #28a745;
    }

    #viewer {
      flex: 1;
      overflow-y: auto;
      background: #eee;
      position: relative;
      -webkit-overflow-scrolling: touch;
    }

    .page-container {
      margin: 10px auto;
      text-align: center;
      min-height: 100px;
      user-select: none;
    }

    .page-container canvas {
      background: white;
      display: block;
      margin: 0 auto;
    }

    #progress {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 1.2em;
      background: rgba(255, 255, 255, 0.8);
      padding: 10px 20px;
      border-radius: 6px;
      z-index: 10;
      pointer-events: none;
    }

    #controls {
      position: fixed;
      bottom: 20px;
      right: 20px;
      z-index: 1000;
      background: rgba(255, 255, 255, 0.9);
      border-radius: 6px;
      box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
      padding: 6px 8px;
      display: flex;
      gap: 8px;
      align-items: center;
    }

    #controls button {
      cursor: pointer;
      border: none;
      background: #28a745;
      color: white;
      font-size: 18px;
      width: 34px;
      height: 34px;
      border-radius: 4px;
    }

    #controls button.toggle-size {
      font-size: 14px;
      padding: 4px 10px;
    }

    #controls button.toggle-thumb {
      background: #666;
      font-size: 14px;
      width: auto;
      padding: 4px 10px;
    }

    #page-input {
      width: 50px;
      font-size: 16px;
      padding: 2px 4px;
      border-radius: 4px;
      border: 1px solid #ccc;
      text-align: center;
    }

    #page-count {
      user-select: none;
      font-size: 16px;
    }
  </style>
</head>

<body>
  <div id="container">
    <div id="thumbnails" class="hidden"></div>
    <div id="viewer" tabindex="0"></div>
  </div>

  <div id="progress">加載中：0%</div>

  <div id="controls" aria-label="PDF Controls">
    <button id="zoom-out" class="toggle-size" title="縮小" aria-label="縮小">−</button>
    <button id="zoom-in" class="toggle-size" title="放大" aria-label="放大">＋</button>
    <button id="toggle-thumbs" class="toggle-thumb" title="切換大綱" aria-label="切換大綱">大綱</button>
    <input type="number" id="page-input" min="1" value="1" aria-label="跳轉頁碼" />
    <span id="page-count" aria-live="polite"></span>
  </div>

  <script src="./pdf.min.js"></script>
  <script>
    (async () => {
      const urlParams = new URLSearchParams(window.location.search);
      const fileUrl = decodeURIComponent(urlParams.get('file') || '');

      if (!fileUrl) {
        alert('文件訪問錯誤');
        return;
      }

      const pdfjsLib = window['pdfjs-dist/build/pdf'];

      pdfjsLib.GlobalWorkerOptions.workerSrc =
        './pdf.worker.min.js';

      const viewer = document.getElementById('viewer');
      const thumbnails = document.getElementById('thumbnails');
      const progressEl = document.getElementById('progress');
      const zoomInBtn = document.getElementById('zoom-in');
      const zoomOutBtn = document.getElementById('zoom-out');
      const toggleThumbBtn = document.getElementById('toggle-thumbs');
      const pageInput = document.getElementById('page-input');
      const pageCountEl = document.getElementById('page-count');

      let pdfDoc = null;
      let currentPage = 1;
      let currentScale = 1.5;
      const minScale = 0.5;
      const maxScale = 4.0;
      const scaleStep = 0.25;

      // 页面渲染状态记录
      const pageRendering = {};

      function updateProgress(percent) {
        progressEl.textContent = `加載中：${percent}%`;
      }

      function clearProgress() {
        progressEl.style.display = 'none';
      }

      function createPageContainer(pageNum) {
        const div = document.createElement('div');
        div.id = 'page-' + pageNum;
        div.className = 'page-container';
        div.style.minHeight = '100px';
        return div;
      }

      function renderPage(pageNum) {
        if (pageRendering[pageNum]) return;
        pageRendering[pageNum] = true;

        pdfDoc.getPage(pageNum).then(page => {
          const viewport = page.getViewport({ scale: currentScale });

          const canvas = document.createElement('canvas');
          const context = canvas.getContext('2d');
          canvas.height = viewport.height;
          canvas.width = viewport.width;

          const renderContext = { canvasContext: context, viewport };
          const renderTask = page.render(renderContext);

          const pageDiv = document.getElementById('page-' + pageNum);
          pageDiv.innerHTML = '';
          pageDiv.appendChild(canvas);
          pageDiv.style.minHeight = viewport.height + 'px';

          return renderTask.promise;
        }).catch(err => {
          console.error(`页面 ${pageNum} 渲染失败`, err);
        }).finally(() => {
          pageRendering[pageNum] = false;
        });
      }

      function createThumbnail(pageNum) {
        const thumbDiv = document.createElement('canvas');
        thumbDiv.id = 'thumb-' + pageNum;
        thumbDiv.title = `第${pageNum}頁`;
        thumbDiv.tabIndex = 0;
        thumbDiv.style.cursor = 'pointer';

        pdfDoc.getPage(pageNum).then(page => {
          const viewport = page.getViewport({ scale: 0.2 });
          const canvas = thumbDiv;
          const ctx = canvas.getContext('2d');
          canvas.width = viewport.width;
          canvas.height = viewport.height;
          page.render({ canvasContext: ctx, viewport });
        });

        thumbDiv.addEventListener('click', () => {
          scrollToPage(pageNum);
        });
        thumbDiv.addEventListener('keydown', e => {
          if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            scrollToPage(pageNum);
          }
        });

        thumbnails.appendChild(thumbDiv);
      }

      function renderAllPages() {
        thumbnails.innerHTML = '';
        viewer.innerHTML = '';
        for (let i = 1; i <= pdfDoc.numPages; i++) {
          const pageDiv = createPageContainer(i);
          viewer.appendChild(pageDiv);
          createThumbnail(i);
        }
        // 初始渲染前几页可视区域的页面
        renderVisiblePages();
      }

      // 简单懒加载：渲染可见页面
      function renderVisiblePages() {
        const buffer = 300; // 预加载缓冲区px
        const scrollTop = viewer.scrollTop;
        const viewportHeight = viewer.clientHeight;

        for (let i = 1; i <= pdfDoc.numPages; i++) {
          const pageEl = document.getElementById('page-' + i);
          if (!pageEl) continue;
          const offsetTop = pageEl.offsetTop;
          if (
            offsetTop + pageEl.offsetHeight >= scrollTop - buffer &&
            offsetTop <= scrollTop + viewportHeight + buffer
          ) {
            renderPage(i);
          }
        }
      }

      function updateActiveThumbnail() {
        for (let i = 1; i <= pdfDoc.numPages; i++) {
          const thumb = document.getElementById('thumb-' + i);
          if (!thumb) continue;
          if (i === currentPage) {
            thumb.classList.add('active');
            thumb.setAttribute('aria-current', 'page');
          } else {
            thumb.classList.remove('active');
            thumb.removeAttribute('aria-current');
          }
        }
      }

      // 滚动监听，更新当前页
      viewer.addEventListener('scroll', () => {
        let minDistance = Infinity;
        let pageNum = currentPage;
        const viewerRect = viewer.getBoundingClientRect();

        for (let i = 1; i <= pdfDoc.numPages; i++) {
          const pageEl = document.getElementById('page-' + i);
          if (!pageEl) continue;
          const rect = pageEl.getBoundingClientRect();
          // 计算距离容器顶部距离的绝对值
          const distance = Math.abs(rect.top - viewerRect.top);
          if (distance < minDistance) {
            minDistance = distance;
            pageNum = i;
          }
        }
        if (pageNum !== currentPage) {
          currentPage = pageNum;
          pageInput.value = currentPage;
          updateActiveThumbnail();
        }
        // renderVisiblePages();
      });

      function scrollToPage(pageNum) {
        const pageEl = document.getElementById('page-' + pageNum);
        if (!pageEl) return;

        currentPage = pageNum;
        updateActiveThumbnail();
        pageInput.value = pageNum;

        // 平滑滚动到页面顶部
        viewer.scrollTo({
          top: pageEl.offsetTop,
          behavior: 'smooth',
        });
      }

      // 重要：缩放并保持当前页顶部位置
      function changeScale(newScale) {
        if (newScale < minScale || newScale > maxScale) return;
        if (newScale === currentScale) return;

        const currentPageEl = document.getElementById('page-' + currentPage);
        if (!currentPageEl) return;

        // 当前滚动条位置和页面顶部相对偏移
        const scrollTopBefore = viewer.scrollTop;
        const offsetTopBefore = currentPageEl.offsetTop;
        const pageTopInView = offsetTopBefore - scrollTopBefore;

        currentScale = newScale;

        // 清空所有页面canvas，重置状态
        for (let i = 1; i <= pdfDoc.numPages; i++) {
          const el = document.getElementById('page-' + i);
          el.innerHTML = '';
          el.style.minHeight = '100px';
          pageRendering[i] = false;
        }

        // 延迟让DOM重新渲染后再设置scrollTop
        setTimeout(() => {
          const currentPageElNew = document.getElementById('page-' + currentPage);
          if (!currentPageElNew) return;

          const offsetTopAfter = currentPageElNew.offsetTop;
          // 计算新的scrollTop，使当前页顶部位置保持不变
          const newScrollTop = offsetTopAfter - pageTopInView;

          viewer.scrollTop = newScrollTop;
          renderVisiblePages();
          updateActiveThumbnail();
        }, 150);
      }

      zoomInBtn.addEventListener('click', () => {
        changeScale(Math.min(currentScale + scaleStep, maxScale));
      });
      zoomOutBtn.addEventListener('click', () => {
        changeScale(Math.max(currentScale - scaleStep, minScale));
      });

      toggleThumbBtn.addEventListener('click', () => {
        if (thumbnails.classList.contains('hidden')) {
          thumbnails.classList.remove('hidden');
          toggleThumbBtn.style.background = '#28a745';
        } else {
          thumbnails.classList.add('hidden');
          toggleThumbBtn.style.background = '#666';
        }
      });

      pageInput.addEventListener('change', () => {
        let val = parseInt(pageInput.value, 10);
        if (isNaN(val) || val < 1) val = 1;
        if (val > pdfDoc.numPages) val = pdfDoc.numPages;
        pageInput.value = val;
        scrollToPage(val);
      });

      // 支持手指捏合缩放
      let pinchStartDist = 0;
      let pinchStartScale = currentScale;
      let isPinching = false;

      viewer.addEventListener('touchstart', e => {
        if (e.touches.length === 2) {
          isPinching = true;
          pinchStartDist = getDistance(e.touches[0], e.touches[1]);
          pinchStartScale = currentScale;
        }
      });

      viewer.addEventListener('touchmove', e => {
        if (isPinching && e.touches.length === 2) {
          const dist = getDistance(e.touches[0], e.touches[1]);
          let scaleChange = dist / pinchStartDist;
          let newScale = pinchStartScale * scaleChange;
          if (newScale < minScale) newScale = minScale;
          if (newScale > maxScale) newScale = maxScale;
          changeScale(newScale);
          e.preventDefault();
        }
      }, { passive: false });

      viewer.addEventListener('touchend', e => {
        if (e.touches.length < 2) {
          isPinching = false;
        }
      });

      function getDistance(t1, t2) {
        const dx = t1.clientX - t2.clientX;
        const dy = t1.clientY - t2.clientY;
        return Math.sqrt(dx * dx + dy * dy);
      }

      // 加载PDF
      try {
        const loadingTask = pdfjsLib.getDocument({
          url: fileUrl,
          // 可加cache:true, range:true等参数按需
        });
        loadingTask.onProgress = (progressData) => {
          const percent = Math.round((progressData.loaded / progressData.total) * 100);
          updateProgress(percent);
        };

        pdfDoc = await loadingTask.promise;

        pageCountEl.textContent = `/ ${pdfDoc.numPages}`;

        renderAllPages();
        clearProgress();

        // 初始显示第一页
        scrollToPage(1);

      } catch (e) {
        progressEl.textContent = '文件加載失敗: ' + e.message;
      }
    })();
  </script>
</body>

</html>